package com.yesep.learn.design.structural.decorator;

import com.yesep.learn.design.common.*;
import com.yesep.learn.design.common.util.*;

/**
 * 装饰器模式（Decorator Pattern），也称为包装模式（Wrapper Pattern），是一种结构型设计模式。
 * 其核心思想是在不改变原有对象结构的基础上，通过动态地给对象添加一些额外的职责来就增加新的功能。
 * 就增加功能来说，装饰器模式相比生成子类更为灵活。
 * <p>
 * 一、定义与原理
 * 装饰器模式允许向一个现有的对象添加新的功能，同时又不改变其结构。就增加功能来说，装饰器模式相比生成子类更为灵活。
 * 这种模式创建了一个包装对象，也就是装饰器，来包裹真实的对象。
 * <p>
 * 二、主要角色
 * 组件接口（Component）：定义了一个对象接口，可以给这些对象动态地添加一些职责。在装饰器模式中，通常是一个抽象类或接口，它定义了被装饰者和装饰者的公共接口。
 * 具体组件（Concrete Component）：实现了组件接口的具体对象，也就是被装饰的对象。
 * 装饰器（Decorator）：持有一个组件（Component）对象的引用，并定义一个与组件接口一致的接口。装饰器类是一个抽象类，用于定义装饰器类必须实现的接口。
 * 具体装饰器（Concrete Decorator）：实现了装饰器接口的具体装饰器对象，负责给组件添加新的功能。
 * 三、优点
 * 灵活性：装饰器模式允许在运行时动态地给对象添加新的功能，而不需要修改原有类的结构，这些功能可以再动态地撤销。
 * 避免子类爆炸：相比使用继承来扩展对象功能，装饰器模式避免了子类膨胀的问题，使得类的继承体系更加简洁。
 * 单一责任原则：每个装饰器类只负责一个特定的功能，遵循了单一责任原则，降低了类的复杂度和耦合度。
 * 开闭原则：装饰器模式对扩展开放，对修改封闭，可以轻松添加新的装饰器来扩展功能。
 * 四、缺点
 * 复杂性：如果过度使用装饰器模式，可能会导致代码变得复杂和难以理解，特别是当存在大量的装饰器和不同的组合方式时。
 * 运行时开销：由于装饰器模式是动态添加功能的，因此可能会在运行时引入一些额外的开销，影响性能。
 * 难以移除特定功能：一旦添加了装饰器，要移除特定功能可能会比较困难，特别是当存在多个装饰器时。
 * 五、应用场景
 * 装饰器模式适用于以下场景：
 * <p>
 * 需要动态地给对象添加新的功能或行为，而不需要修改原有类的结构。
 * 需要避免创建大量子类来实现不同的功能组合，导致类爆炸。
 * 需要遵循开闭原则，在不修改现有代码的情况下扩展功能。
 * 需要在运行时动态地添加或移除功能，以满足不同的需求。
 * 六、示例
 * 以咖啡添加配料为例，可以使用装饰器模式为咖啡添加不同的配料，如牛奶、糖等。在这个例子中，咖啡是具体组件，而牛奶和糖则是具体装饰器。
 * 通过组合不同的装饰器，我们可以为咖啡添加不同的配料，而不需要修改咖啡类的结构。
 */

public class Main {
    public static void main(String[] args) throws Exception {
        String mp3 = "hello.mp3";
        String mp4 = "hello.mp4";
        IMediaPlayer audioPlayer = DemoUtil.createAudioPlayer();
        MediaPlayerSubtitleDecorator audioMediaPlayerSubtitleDecorator = new MediaPlayerSubtitleDecorator(audioPlayer);
        audioMediaPlayerSubtitleDecorator.play(mp3);

        IMediaPlayer videoPlayer = DemoUtil.createVideoPlayer();
        MediaPlayerSubtitleDecorator videoMediaPlayerSubtitleDecorator = new MediaPlayerSubtitleDecorator(videoPlayer);
        videoMediaPlayerSubtitleDecorator.play(mp4);
    }
}
